package org.one.stone.soup.db.indexing;

import java.util.ArrayList;
import java.util.List;

import org.one.stone.soup.db.processors.JSON;

public class GISDataIndex implements Index {

	public class GISEntry {
		
		GISEntry(long id,double latitude,double longitude) {
			this.latitude = latitude;
			this.longitude = longitude;
			this.id = id;
		}
		
		double latitude;
		double longitude;
		long id;
	}
	
	private List<GISEntry> list;
	
	public void index(long id,double latitiude,double longitude) {
		GISEntry entry = new GISEntry(id,latitiude,longitude);
		list.add(entry);
	}
	
	public long findNearest(double latitiude,double longitude) {
		return 0;
	}
	
	public Long[] findInArea(double latitudeA,double longitudeA,double latitudeB,double longitudeB) {
		List<Long> latitudeSet = findWithinLatitudeRange(latitudeA, latitudeB);
		List<Long> longitudeSet = findWithinLongitudeRange(longitudeA, longitudeB);
		
		return SetCombiner.findCommonSet(latitudeSet,longitudeSet).toArray(new Long[]{});
	}
	
	public Long[] findInArea(double latitude,double longitude,double radius) {
		double latitudeA = latitude-radius;
		double longitudeA = longitude-radius;
		
		double latitudeB = latitude+radius;
		double longitudeB = longitude+radius;
		
		List<Long> latitudeSet = findWithinLatitudeRange(latitudeA, latitudeB);
		List<Long> longitudeSet = findWithinLongitudeRange(longitudeA, longitudeB);
		List<Long> areaSet = SetCombiner.findCommonSet(latitudeSet,longitudeSet);
		
		GISEntry location = new GISEntry(-1,latitude,longitude);
		List<Long> result = new ArrayList<Long>();
		for(Long id: areaSet) {
			GISEntry entry = findEntry(id);
			if( distance(location,entry)<=radius ) {
				result.add(id);
			}
		}
		return result.toArray(new Long[]{});
	}

	private double distance(GISEntry entryA,GISEntry entryB) {
		double dLat = entryB.latitude - entryA.latitude;
		double dLong = entryB.longitude - entryA.longitude;
		
		double distance = Math.pow((dLat*dLat)+(dLong*dLong), 0.5);
		return distance;
	}
	
	private GISEntry findEntry(long id) {
		for(GISEntry entry: list) {
			if(entry.id==id) {
				return entry;
			}
		}
		return null;
	}
	
	public void index(long index, JSON json) {
		index( index,json.getDouble("latitude"),json.getDouble("longitude") );
	}
	
	private List<Long> findWithinLongitudeRange(double longitudeA,double longitudeB) {
		List<Long> result = new ArrayList<Long>();
		for(GISEntry entry: list) {
			if(entry.longitude >= longitudeA && entry.longitude <= longitudeB) {
				result.add(entry.id);
			}
		}
		return result;
	}
	
	private List<Long> findWithinLatitudeRange(double latitudeA,double latitudeB) {
		List<Long> result = new ArrayList<Long>();
		for(GISEntry entry: list) {
			if(entry.latitude >= latitudeA && entry.latitude <= latitudeB) {
				result.add(entry.id);
			}
		}
		return result;
	}
}
